home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / AX25SUBR.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  10KB  |  430 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "timer.h"
  5. #include "ax25.h"
  6. #include "lapb.h"
  7. #include <ctype.h>
  8.  
  9. static int16 ax25hash __ARGS((struct ax25_addr *s));
  10.  
  11. struct ax25_cb *Ax25_cb[NHASH];
  12.  
  13. /* Default AX.25 parameters */
  14. int32 T3init = 0;        /* No keep-alive polling */
  15. int16 Maxframe = 1;        /* Stop and wait */
  16. int16 N2 = 10;            /* 10 retries */
  17. int16 Axwindow = 2048;        /* 2K incoming text before RNR'ing */
  18. int16 Paclen = 256;        /* 256-byte I fields */
  19. int16 Pthresh = 128;        /* Send polls for packets larger than this */
  20. int32 Axirtt = 5000;        /* Initial round trip estimate, ms */
  21. int16 Axversion = V1;        /* Protocol version */
  22.  
  23. /* Address hash function. Exclusive-ORs each byte, ignoring
  24.  * such insignificant, annoying things as E and H bits
  25.  */
  26. static int16
  27. ax25hash(s)
  28. struct ax25_addr *s;
  29. {
  30.     register unsigned x;
  31.     register int i;
  32.     register char *cp;
  33.  
  34.     x = 0;
  35.     cp = s->call;
  36.     for(i=ALEN; i!=0; i--)
  37.         x ^= *cp++;
  38.     x &= 0xfe;
  39.     x ^= s->ssid & SSID;
  40.     return uchar(x) % NHASH;
  41. }
  42. /* Look up entry in hash table */
  43. struct ax25_cb *
  44. find_ax25(addr)
  45. register struct ax25_addr *addr;
  46. {
  47.     int16 hashval;
  48.     register struct ax25_cb *axp;
  49.  
  50.     /* Find appropriate hash chain */
  51.     hashval = ax25hash(addr);
  52.  
  53.     /* Search hash chain */
  54.     for(axp = Ax25_cb[hashval]; axp != NULLAX25; axp = axp->next){
  55.         if(addreq(&axp->remote,addr)){
  56.             return axp;
  57.         }
  58.     }
  59.     return NULLAX25;
  60. }
  61.  
  62. /* Remove address entry from hash table */
  63. void
  64. del_ax25(axp)
  65. register struct ax25_cb *axp;
  66. {
  67.     int16 hashval;
  68.  
  69.     if(axp == NULLAX25)
  70.         return;
  71.     /* Remove from hash header list if first on chain */
  72.     hashval = ax25hash(&axp->remote);
  73.  
  74.     /* Remove from chain list */
  75.     if(axp->prev == NULLAX25)
  76.         Ax25_cb[hashval] = axp->next;
  77.     else
  78.         axp->prev->next = axp->next;
  79.     if(axp->next != NULLAX25)
  80.         axp->next->prev = axp->prev;
  81.  
  82.     /* Timers should already be stopped, but just in case... */
  83.     stop_timer(&axp->t1);
  84.     stop_timer(&axp->t3);
  85.  
  86.     /* Free allocated resources */
  87.     free_q(&axp->txq);
  88.     free_q(&axp->rxasm);
  89.     free_q(&axp->rxq);
  90.     free((char *)axp);
  91. }
  92.  
  93. /* Create an ax25 control block. Allocate a new structure, if necessary,
  94.  * and fill it with all the defaults. The caller
  95.  * is still responsible for filling in the reply address
  96.  */
  97. struct ax25_cb *
  98. cr_ax25(addr)
  99. struct ax25_addr *addr;
  100. {
  101.     register struct ax25_cb *axp;
  102.     int16 hashval;
  103.  
  104.     if(addr == NULLAXADDR)
  105.         return NULLAX25;
  106.  
  107.     if((axp = find_ax25(addr)) == NULLAX25){
  108.         /* Not already in table; create an entry
  109.          * and insert it at the head of the chain
  110.          */
  111.         /* Find appropriate hash chain */
  112.         hashval = ax25hash(addr);
  113.         axp = (struct ax25_cb *)calloc(1,sizeof(struct ax25_cb));
  114.         if(axp == NULLAX25)
  115.             return NULLAX25;
  116.         /* Insert at beginning of chain */
  117.         axp->next = Ax25_cb[hashval];
  118.         if(axp->next != NULLAX25)
  119.             axp->next->prev = axp;
  120.         Ax25_cb[hashval] = axp;
  121.     }
  122.     axp->user = -1;
  123.     axp->state = DISCONNECTED;
  124.     axp->maxframe = Maxframe;
  125.     axp->window = Axwindow;
  126.     axp->paclen = Paclen;
  127.     axp->proto = Axversion;    /* Default, can be changed by other end */
  128.     axp->pthresh = Pthresh;
  129.     axp->n2 = N2;
  130.     axp->srt = Axirtt / MSPTICK;
  131.     axp->t1.start = 2*axp->srt;
  132.     axp->t1.func = recover;
  133.     axp->t1.arg = axp;
  134.  
  135.     axp->t3.start = T3init / MSPTICK;
  136.     axp->t3.func = pollthem;
  137.     axp->t3.arg = axp;
  138.  
  139.     /* Always to a receive and state upcall as default */
  140.     axp->r_upcall = s_arcall;
  141.     axp->s_upcall = s_ascall;
  142.  
  143.     return axp;
  144. }
  145.  
  146. /*
  147.  * setcall - convert callsign plus substation ID of the form
  148.  * "KA9Q-0" to AX.25 (shifted) address format
  149.  *   Address extension bit is left clear
  150.  *   Return -1 on error, 0 if OK
  151.  */
  152. int
  153. setcall(out,call)
  154. struct ax25_addr *out;
  155. char *call;
  156. {
  157.     int csize;
  158.     unsigned ssid;
  159.     register int i;
  160.     register char *cp,*dp;
  161.     char c;
  162.  
  163.     if(out == (struct ax25_addr *)NULL || call == NULLCHAR || *call == '\0'){
  164.         return -1;
  165.     }
  166.     /* Find dash, if any, separating callsign from ssid
  167.      * Then compute length of callsign field and make sure
  168.      * it isn't excessive
  169.      */
  170.     dp = strchr(call,'-');
  171.     if(dp == NULLCHAR)
  172.         csize = strlen(call);
  173.     else
  174.         csize = dp - call;
  175.     if(csize > ALEN)
  176.         return -1;
  177.     /* Now find and convert ssid, if any */
  178.     if(dp != NULLCHAR){
  179.         dp++;    /* skip dash */
  180.         ssid = atoi(dp);
  181.         if(ssid > 15)
  182.             return -1;
  183.     } else
  184.         ssid = 0;
  185.     /* Copy upper-case callsign, left shifted one bit */
  186.     cp = out->call;
  187.     for(i=0;i<csize;i++){
  188.         c = *call++;
  189.         if(islower(c))
  190.             c = toupper(c);
  191.         *cp++ = c << 1;
  192.     }
  193.     /* Pad with shifted spaces if necessary */
  194.     for(;i<ALEN;i++)
  195.         *cp++ = ' ' << 1;
  196.     
  197.     /* Insert substation ID field and set reserved bits */
  198.     out->ssid = 0x60 | (ssid << 1);
  199.     return 0;
  200. }
  201. /* Set an ARP table entry */
  202. int
  203. setpath(out,in)
  204. char *out;    /* Target char array containing addresses in net form */
  205. char *in;    /* Input array of tokenized callsigns in ASCII */
  206. {
  207.     struct ax25_addr addr;
  208.  
  209.     setcall(&addr,in);
  210.     out = putaxaddr(out,&addr);
  211.     return 0;
  212. }
  213. int
  214. addreq(a,b)
  215. register struct ax25_addr *a,*b;
  216. {
  217.     if(memcmp(a->call,b->call,ALEN) != 0)
  218.         return 0;
  219.     if((a->ssid & SSID) != (b->ssid & SSID))
  220.         return 0;
  221.     return 1;
  222. }
  223. /* Convert encoded AX.25 address to printable string */
  224. int
  225. pax25(e,addr)
  226. char *e;
  227. struct ax25_addr *addr;
  228. {
  229.     register int i;
  230.     char c,*cp;
  231.  
  232.     cp = addr->call;
  233.     for(i=ALEN;i != 0;i--){
  234.         c = (*cp++ >> 1) & 0x7f;
  235.         if(c == ' ')
  236.             break;
  237.         *e++ = c;
  238.     }
  239.     if ((addr->ssid & SSID) != 0)
  240.         sprintf(e,"-%d",(addr->ssid >> 1) & 0xf);    /* ssid */
  241.     else
  242.         *e = 0;
  243.     return 0;
  244. }
  245. /* Print an AX.25 address
  246.  * Designed for use by ARP - arg is a char string
  247.  */
  248. int
  249. psax25(e,addr)
  250. register char *e;
  251. register char *addr;
  252. {
  253.     struct ax25_addr axaddr;
  254.  
  255.     /* Create local copy in host-format structure */
  256.     addr = getaxaddr(&axaddr,addr);
  257.  
  258.     pax25(e,&axaddr);
  259.     return 0;
  260. }
  261. char *
  262. getaxaddr(ap,cp)
  263. register struct ax25_addr *ap;
  264. register char *cp;
  265. {
  266.     memcpy(ap->call,cp,ALEN);
  267.     cp += ALEN;
  268.     ap->ssid = *cp++;
  269.     return cp;
  270. }
  271. char *
  272. putaxaddr(cp,ap)
  273. register char *cp;
  274. register struct ax25_addr *ap;
  275. {
  276.     memcpy(cp,ap->call,ALEN);
  277.     cp += ALEN;
  278.     *cp++ = ap->ssid;
  279.     return cp;
  280. }
  281.  
  282. /* Convert a host-format AX.25 header into a mbuf ready for transmission */
  283. struct mbuf *
  284. htonax25(hdr,data)
  285. register struct ax25 *hdr;
  286. struct mbuf *data;
  287. {
  288.     struct mbuf *bp;
  289.     register char *cp;
  290.     register int16 i;
  291.  
  292.     if(hdr == (struct ax25 *)NULL || hdr->ndigis > MAXDIGIS)
  293.         return NULLBUF;
  294.  
  295.     /* Allocate space for return buffer */
  296.     i = AXALEN * (2 + hdr->ndigis);
  297.     if((bp = pushdown(data,i)) == NULLBUF)
  298.         return NULLBUF;
  299.  
  300.     /* Now convert */
  301.     cp = bp->data;
  302.  
  303.     hdr->dest.ssid &= ~E;    /* Dest E-bit is always off */
  304.     /* Encode command/response in C bits */
  305.     switch(hdr->cmdrsp){
  306.     case COMMAND:
  307.         hdr->dest.ssid |= C;
  308.         hdr->source.ssid &= ~C;
  309.         break;
  310.     case RESPONSE:
  311.         hdr->dest.ssid &= ~C;
  312.         hdr->source.ssid |= C;
  313.         break;
  314.     default:
  315.         hdr->dest.ssid &= ~C;
  316.         hdr->source.ssid &= ~C;
  317.         break;
  318.     }
  319.     cp = putaxaddr(cp,&hdr->dest);
  320.  
  321.     /* Set E bit on source address if no digis */
  322.     if(hdr->ndigis == 0){
  323.         hdr->source.ssid |= E;
  324.         putaxaddr(cp,&hdr->source);
  325.         return bp;
  326.     }
  327.     hdr->source.ssid &= ~E;
  328.     cp = putaxaddr(cp,&hdr->source);
  329.  
  330.     /* All but last digi get copied with E bit off */
  331.     for(i=0; i < hdr->ndigis - 1; i++){
  332.         hdr->digis[i].ssid &= ~E;
  333.         cp = putaxaddr(cp,&hdr->digis[i]);
  334.     }
  335.     hdr->digis[i].ssid |= E;
  336.     cp = putaxaddr(cp,&hdr->digis[i]);
  337.     return bp;
  338. }
  339. /* Convert an AX.25 ARP table entry into a host format address structure
  340.  * ready for use in transmitting a packet
  341.  */
  342. int
  343. atohax25(hdr,hwaddr,source)
  344. register struct ax25 *hdr;
  345. register char *hwaddr;
  346. struct ax25_addr *source;
  347. {
  348.     register struct ax25_addr *axp;
  349.  
  350.     hwaddr = getaxaddr(&hdr->dest,hwaddr);    /* Destination address */
  351.     ASSIGN(hdr->source,*source);        /* Source address */
  352.     if(hdr->dest.ssid & E){
  353.         /* No digipeaters */
  354.         hdr->ndigis = 0;
  355.         hdr->dest.ssid &= ~E;
  356.         hdr->source.ssid |= E;
  357.         return 2;
  358.     }
  359.     hdr->source.ssid &= ~E;
  360.     hdr->dest.ssid &= ~E;
  361.     for(axp = hdr->digis; axp < &hdr->digis[MAXDIGIS]; axp++){
  362.         hwaddr = getaxaddr(axp,hwaddr);
  363.         if(axp->ssid & E){
  364.             hdr->ndigis = axp - hdr->digis + 1;
  365.             return hdr->ndigis;
  366.         }
  367.     }
  368.     return -1;
  369. }
  370. /* Convert a network-format AX.25 header into a host format structure
  371.  * Return -1 if error, number of addresses if OK
  372.  */
  373. int
  374. ntohax25(hdr,bpp)
  375. register struct ax25 *hdr;    /* Output structure */
  376. struct mbuf **bpp;
  377. {
  378.     register struct ax25_addr *axp;
  379.     char buf[AXALEN];
  380.  
  381.     if(pullup(bpp,buf,AXALEN) < AXALEN)
  382.         return -1;
  383.     getaxaddr(&hdr->dest,buf);
  384.  
  385.     if(pullup(bpp,buf,AXALEN) < AXALEN)
  386.         return -1;
  387.     getaxaddr(&hdr->source,buf);
  388.  
  389.     /* Process C bits to get command/response indication */
  390.     if((hdr->source.ssid & C) == (hdr->dest.ssid & C))
  391.         hdr->cmdrsp = UNKNOWN;
  392.     else if(hdr->source.ssid & C)
  393.         hdr->cmdrsp = RESPONSE;
  394.     else
  395.         hdr->cmdrsp = COMMAND;
  396.  
  397.     hdr->ndigis = 0;
  398.     if(hdr->source.ssid & E)
  399.         return 2;    /* No digis */
  400.  
  401.     /* Process the digipeaters */
  402.     for(axp = hdr->digis;axp < &hdr->digis[MAXDIGIS]; axp++){
  403.         if(pullup(bpp,buf,AXALEN) < AXALEN){
  404.             return -1;
  405.         }
  406.         getaxaddr(axp,buf);
  407.         if(axp->ssid & E){    /* Last one */
  408.             hdr->ndigis = axp - hdr->digis + 1;
  409.             return hdr->ndigis + 2;            
  410.         }
  411.     }
  412.     return -1;    /* Too many digis */
  413. }
  414.  
  415. /* Figure out the frame type from the control field
  416.  * This is done by masking out any sequence numbers and the
  417.  * poll/final bit after determining the general class (I/S/U) of the frame
  418.  */
  419. int16
  420. ftype(control)
  421. register char control;
  422. {
  423.     if((control & 1) == 0)    /* An I-frame is an I-frame... */
  424.         return I;
  425.     if(control & 2)        /* U-frames use all except P/F bit for type */
  426.         return(control & ~PF);
  427.     else            /* S-frames use low order 4 bits for type */
  428.         return(control & 0xf);
  429. }
  430.